﻿using System.Text.Json;
using Microsoft.AspNetCore.Mvc;

namespace OpenAIProxy;

[ApiController]
[Route("v1/chat/completions")]
public class OpenAIProxyController : ControllerBase
{
    private readonly HttpClient _client;
    private readonly IStorageService _storage;
    private readonly ITokenCounter _tokenCounter;
    private readonly ILogger<OpenAIProxyController> _logger;
    private readonly IFileStorage _fileStorage;
    // private readonly ILogger<OpenAIProxyController> _logger;
    // private readonly IStorageService _storage;
    // private readonly ITokenCounter _tokenCounter;
    private readonly OpenAIServiceSelector _serviceSelector;
    private readonly OpenAIHttpClientFactory _httpClientFactory;
    private readonly ConfigManager _configManager;
    public OpenAIProxyController(
        // IHttpClientFactory httpClientFactory,
        IStorageService storage,
        ITokenCounter tokenCounter,
        ILogger<OpenAIProxyController> logger,
        IFileStorage fileStorage,
        OpenAIServiceSelector serviceSelector,
        OpenAIHttpClientFactory httpClientFactory,
        ConfigManager configManager)
    {
        // _client = httpClientFactory.CreateClient("OpenAI");
        _storage = storage;
        _tokenCounter = tokenCounter;
        _logger = logger;
        _fileStorage = fileStorage;
        //_logger = logger;
        //_storage = storage;
        //_tokenCounter = tokenCounter;
        _serviceSelector = serviceSelector;
        _configManager = configManager;
        _httpClientFactory = httpClientFactory;
    }

    [HttpPost]
    public async Task<IActionResult> PostAsync([FromBody] OpenAIChatRequest request)
    {
        if (string.IsNullOrEmpty(request.Model))
        {
            return BadRequest("模型名称必填");
        }
        
        var (provider, modelConfig) = _serviceSelector.SelectProvider(request);
        if (provider == null || modelConfig == null)
        {
            return BadRequest($"模型 {request.Model} 没有可用的提供商");
        }
        
        try
        {
            await _fileStorage.LogInformationAsync($"收到请求: {JsonSerializer.Serialize(request)}");
            
            var promptTokens = request.Messages.Sum(m => _tokenCounter.CalculateTokens(m.Content));
            
            var record = new ChatRecord
            {
                Request = JsonSerializer.Serialize(request),
                PromptTokens = promptTokens,
                Provider = provider.Name,
                Model = request.Model
            };
            
            var httpClient = _httpClientFactory.GetHttpClient(provider.Name);
            // var requestUri = "chat/completions";
            var requestUri = "";
            var httpRequest = new HttpRequestMessage(HttpMethod.Post, requestUri)
            {
                Content = JsonContent.Create(request)
            };
            
            if (request.Stream ?? false)
            {
                return await HandleStreamingRequest(
                    httpClient, httpRequest, record, modelConfig);
            }
            else
            {
                return await HandleNonStreamingRequest(
                    httpClient, httpRequest, record, modelConfig);
            }
            
            if (request.Stream.HasValue && request.Stream.Value)
                return await HandleStreamingRequest(request, record);
            
            var response = await _client.PostAsJsonAsync("", request);
            var responseBody = await response.Content.ReadAsStringAsync();
            
            if (!response.IsSuccessStatusCode)
            {
                _logger.LogError($"OpenAI API错误: {response.StatusCode} - {responseBody}");
                return StatusCode((int)response.StatusCode, responseBody);
            }

            var result = JsonSerializer.Deserialize<OpenAIChatResponse>(responseBody);
            var reply = result?.Choices?.FirstOrDefault()?.Message?.Content;
            
            var completionTokens = _tokenCounter.CalculateTokens(reply);
            
            await _storage.SaveRecordAsync(record);

            return Content(responseBody, "application/json");
        }
        catch (Exception ex)
        {
            await _fileStorage.LogErrorAsync($"处理请求失败: {ex.ToString()}");
            return StatusCode(500, "内部服务器错误");
        }
    }
    
    private async Task<IActionResult> HandleStreamingRequest(OpenAIChatRequest request, ChatRecord record)
    {
        var tokenAccumulator = new TokenAccumulator(_tokenCounter);
        
        var httpRequest = new HttpRequestMessage(HttpMethod.Post, "")
        {
            Content = JsonContent.Create(request)
        };
        
        var response = await _client.SendAsync(httpRequest, HttpCompletionOption.ResponseHeadersRead);
        
        if (!response.IsSuccessStatusCode)
        {
            var errorContent = await response.Content.ReadAsStringAsync();
            _logger.LogError($"OpenAI API错误: {response.StatusCode} - {errorContent}");
            return StatusCode((int)response.StatusCode, errorContent);
        }
        
        var result = new EventStreamResponse(response, tokenAccumulator, record,0);
        _ = StoreRecordAfterCompletion(record);
        return result;
    }
    
    private async Task StoreRecordAfterCompletion(ChatRecord record)
    {
        await Task.Delay(1000);
        await _storage.SaveRecordAsync(record);
    }
    
    private async Task<IActionResult> HandleStreamingRequest(
        HttpClient httpClient,
        HttpRequestMessage httpRequest,
        ChatRecord record,
        ModelConfig modelConfig)
    {
        try
        {
            var tokenAccumulator = new TokenAccumulator(_tokenCounter);
            
            // 发送请求并获得响应
            var response = await httpClient.SendAsync(
                httpRequest,
                HttpCompletionOption.ResponseHeadersRead);
            
            if (!response.IsSuccessStatusCode)
            {
                return HandleErrorResponse(response, "流式请求");
            }
            
            // 返回到客户端的流式结果
            var result = new EventStreamResponse(
                response, tokenAccumulator, record, modelConfig.CostPerToken);
            _ = StoreRecordAfterCompletion(record);
            return result;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "处理流式请求失败");
            return StatusCode(500, "内部服务器错误");
        }
    }
    
    private async Task<IActionResult> HandleNonStreamingRequest(
        HttpClient httpClient,
        HttpRequestMessage httpRequest,
        ChatRecord record,
        ModelConfig modelConfig)
    {
        try
        {
            // 发送请求并获得响应
            var response = await httpClient.SendAsync(httpRequest);
            var responseBody = await response.Content.ReadAsStringAsync();
            
            if (!response.IsSuccessStatusCode)
            {
                return HandleErrorResponse(response, "非流式请求");
            }
            
            // 提取响应数据
            var jsonResponse = JsonDocument.Parse(responseBody);
            var choices = jsonResponse.RootElement.GetProperty("choices");
            
            // 计算完成Token和成本
            var content = choices[0].GetProperty("message").GetProperty("content").GetString()!;
            record.Response = content;
            record.CompletionTokens = _tokenCounter.CalculateTokens(content);
            record.Cost = CalculateCost(record, modelConfig.CostPerToken);
            // 保存记录
            await _storage.SaveRecordAsync(record);
            
            // 返回响应
            return Content(responseBody, "application/json");
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "处理非流式请求失败");
            return StatusCode(500, "内部服务器错误");
        }
    }
    
    private decimal CalculateCost(ChatRecord record, decimal modelCostPerToken)
    {
        return (record.PromptTokens + record.CompletionTokens) * modelCostPerToken;
    }
    
    private IActionResult HandleErrorResponse(
        HttpResponseMessage response, 
        string requestType)
    {
        var statusCode = (int)response.StatusCode;
        var errorContent = response.Content.ReadAsStringAsync().Result;
        _logger.LogError($"{requestType}错误: {statusCode} - {errorContent}");
        return StatusCode(statusCode, errorContent);
    }
}